///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//				mapas.c
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#include "../inc/mapas.h"

// Para agregat un nuevo tipo de objeto hay que agregarlo en mapas.h con su correspondiente probabilidad
// y hay que agregarlo a estas funciones: initswitch; objecttest; drawij
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//initswitch: determina cual es el initobject. recive el objeto inicializador deseado (q fue introducido por consola).
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int initswitch (char *p)
{		
	switch (*p)							     //TIPOS DE OBJETOS (AGREGAR ACA SI SE AGREGA UNO NUEVO)
	{	
		case 'P':	
			initmap(PASTO);
			break;
		case 'W':
			initmap(AGUA);
			break;
		case 'A':
			initmap(ARBOL);
			break;
		default:
			printf("\nla cagaste mon, no existe ese tipo de objeto\n");
			printf("Tipos existentes:\n\t'P' PASTO\n\t'W' AGUA\n\t'A' ARBOL\n");           
			errflag=1;
			break;
	}
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Initmap: recibe el objeto con el que se va a inicializar (llenar) el mapa. lo llena con ese objeto. a prueba de boludos.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int initmap(int object)
{
	initobj=object;  				//almaceno el objeto inicializador (draw lo usa dps)	
	for (i=0;i<MAXMH;++i)				// recorro todas las casillas del mapa
		for (j=0;j<MAXMW;j++)			// recorro todas las casillas del mapa
			map[i][j]=(char*)object;			
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//drawmap: "dibuja azarosamente un mapa"
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int drawmap (void)
{
	for (i=0;i<MAXMH;++i)				// recorro todas las casillas del mapa
		for (j=0;j<MAXMW;j++)			// recorro todas las casillas del mapa
		{
			obj=objecttest();
			tempi=i;			//guardo i
			tempj=j;			//guardo j		
			drawij(i,j,obj);		//dibujo ij, doh!
			i=tempi;			//recupero i
			j=tempj;			//recuepero j
		}					
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// checkij: chequea que el ij seleccionado no tenga ningun objeto distinto del inicializado. de esta manera, 
// se evita que se 'sobreescriba' una casilla..
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int checkij ( char*p)		//recive puntero a la casilla ij
{	
	if (*p == initobj)	//si la casilla ij tiene el mismo objeto que el inicializado
		return OK;	//entonces devuelve OK
	else			//sino	
		return ERR;	//devuelve error(en este caso, no se dibuja nada en la casilla ij, y se avanza hacia otra casilla
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//drawtest: hace la prueba de dibujo. si pasa, entonces se dibuja algo en casilla ij, sino no se dibuja nada
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int drawtest (int coef)
{
	if ( randmn(0,1) < PROB_DIBUJE*coef)
		return OK;
	else
		return ERR;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//objecttest:realiza prueba para ver que objecto se dibuja en ij. para agregar mas objetos ver mapas.h y aca abajo
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int objecttest(void)
{
	double randnum=randmn(0,1);				//numero random 
	int returnvar=0;
	switch (initobj)							     //TIPOS DE OBJETOS (AGREGAR ACA SI SE AGREGA UNO NUEVO)
	{	
		case '#':	
			if ( (0 <= randnum) && (randnum < PROB_ARBOL) )				//si el numero esta en el intervalo de ARBOL
				returnvar = ARBOL;							// entonces dibujo ARBOl
			if ( (PROB_ARBOL <= randnum) && (randnum < PROB_ARBOL + PROB_AGUA) )	//si esta en el intervalo AGUA
				returnvar = AGUA;							//dibujo AGUA
			break;
		case 'W':
			if ( (0 <= randnum) && (randnum < PROB_ARBOL) )				//si el numero esta en el intervalo de ARBOL
				returnvar = ARBOL;							// entonces dibujo ARBOl
			if ( (PROB_ARBOL <= randnum) && (randnum < PROB_ARBOL + PROB_PASTO) )	//si esta en el intervalo PASTO
				returnvar = PASTO;							//dibujo PASTO
			break;
		case 'A':
			if ( (0 <= randnum) && (randnum < PROB_PASTO) )				//si el numero esta en el intervalo de PASTO
				returnvar = PASTO;							// entonces dibujo PASTO
			if ( (PROB_PASTO <= randnum) && (randnum < PROB_PASTO + PROB_AGUA) )	//si esta en el intervalo AGUA
				returnvar = AGUA;							//dibujo AGUA
			break;
		default:
			printf("\n Error en objecttest.\n");
			break;
	}	
	return returnvar;							 
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////	
//printmap: imprime el mapa en pantalla
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int printmap (void)
{
	for (i=0;i<MAXMH;++i)				// recorro todas las casillas del mapa
	{	for (j=0;j<MAXMW;j++)			// recorro todas las casillas del mapa
			printf ("%c ",map[i][j]);	//imprimo en pantalla lo que este en ij.
		printf("\n");
	}
	return 0;
}


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// Drawij: dibuja ij, si es agua o arbol dibuja en un entorno de ij mediante a desplazamientos en el eje i o j. 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int drawij (int i, int j,int obj)
{	i = tempi;			//esto es para que los desplazamientos de ij esten centrados en el ij original
	j = tempj;			//idem arriba	
	if (checkij(&map[i][j]) == OK ) //evita que se trate de agregar un objeto de un tipo distinto al inicializado donde ya habia uno
	{				// es para no sobreescribir una casilla
		if ( (drawtest(1.5) == OK ))	//le aumento al 1.5 la probabilidad porque se me cantó.
		{	switch (obj)							 
			{	
	//////////// Modo 1: los desplazamientos son en un solo eje, i o j.	////////////////////////////////////////////////////////
	//////////////// esto hace que no puedas moverte en diagonal en 1 solo movimiento///////////////////////////////////////////////
				case 'A':
					map[i][j] = (char*) obj;	// "dibuja" en ij el objeto devuelto por objecttest	
					if ( randmn(0,1) < 0.5)					
						drawij (i,randj(j),obj);	//se recursiona al infintio y mas alla
					else
						drawij (randi(i),j,obj);			
					break;
				case 'W':
					map[i][j] = (char*) obj;	// "dibuja" en ij el objeto devuelto por objecttest			
					if ( randmn(0,1) < 0.5)					
						drawij (i,randj(j),obj);	//se recursiona al infintio y mas alla
					else
						drawij (randi(i),j,obj);					
					break;
				case '#':
					map[i][j] = (char*) obj;
					break;
	/////////// fin del modo 1 //////////////////////////////////////////////////////////////////////////////////////////////////////////	
	///////// modo 2 : permite moverse en diagonal en 1 solo movimiento
			      /*case 'A':
					map[i][j] = (char*) obj;	// "dibuja" en ij el objeto devuelto por objecttest	
					drawij (randi(i),randj(j),obj);	//se recursiona al infintio y mas alla			
					break;
				case 'W':
					map[i][j] = (char*) obj;	// "dibuja" en ij el objeto devuelto por objecttest			
					drawij (randi(i),randj(j),obj);					
					break;
				case '#':
					map[i][j] = (char*) obj;
					break;*/
	////////////// fin del modo 2 //////////////////////////////////////////////////////////////////////////////////////////////////////
			}						
		}						
	} 
} //cuantos corchetes che...
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// randi: genera el desplazamiento en el eje i al azar para drawij
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int randi (int i)
{	int auxi=0;
	switch (randn(1))
	{
		case '0': 
			auxi = ((--i>=0)?i:++i); //chequea que no se haya ido fuera del mapa
			break;
		case '1':
			auxi = ((++i<=MAXMH)?i:--i); //chequea que no se haya ido fuera del mapa
			break;
	}
	return auxi;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
///// randj: genera el desplazamiento en el eje j al azar para drawij
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int randj (int j)
{	int auxj=0;
	switch (randn(1))
	{
		case '0': 
			auxj = ((--j>=0)?j:++j);         //chequea que no se haya ido fuera del mapa
		case '1':
			auxj = ((++j<=MAXMW)?j:--j);        //chequea que no se haya ido fuera del mapa
	}
	return auxj;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//randn: devuelve un numero aleatorio ENTERO entre 0 y n. 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
int randn(int n)
{	
	return ( (int) ((double)rand() / ((double)RAND_MAX + 1) *n) );
}

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//randmn: genera numero aleatorio FLOAT entre m y n (m<n). 
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
inline double randmn (double m, double n)
{
	return m + (n - m) * rand() / ((double) RAND_MAX);
}

